use std::{io::{Read, Write}};

use cross_rs::IResult;
use flate2::{read::GzDecoder, write::GzEncoder, Compression};

use crate::disk::file_io;


pub fn unzip_file_to_bytes(file_gz: &str) -> IResult<Vec<u8>> {
    let bts_gz = file_io::read_bytes(file_gz)?;
    
    let mut gz = GzDecoder::new(&bts_gz[..]);
    let mut bts_raw = vec![];
    if let Err(e) = gz.read_to_end(&mut bts_raw) {
        return Err(format!("gzip::decode_file {file_gz} error: {:?}", e).as_str())?;
    }
    Ok(bts_raw)
}

// pub fn compress_file() {
//     let file_raw = "D:/temp/2000977.bin";
//     let file_gz = "D:/temp/2000977.bin.gz";
//     let mut input = BufReader::new(File::open(file_raw).unwrap());
//     let output = File::create(file_gz).unwrap();
    
//     let mut encoder = GzEncoder::new(output, Compression::default());
//     let start = Instant::now();
//     copy(&mut input, &mut encoder).unwrap();
//     let output = encoder.finish().unwrap();
//     println!(
//         "Source len: {:?}",
//         input.get_ref().metadata().unwrap().len()
//     );
//     println!("Target len: {:?}", output.metadata().unwrap().len());
//     println!("Elapsed: {:?}", start.elapsed());
// }


pub fn zip_bytes_to_file(bts_raw: Vec<u8>, file_gz: &str) -> IResult {
    let mut encoder = GzEncoder::new(vec![], Compression::default());
    // let start = TimeInt::now();
    match encoder.write_all(&bts_raw) {
        Ok(_) => (),
        Err(e) => return Err(format!("gzip::zip_bytes_to_file {file_gz} encoding error: {:?}", e).as_str())?,
    }
    // let millsec1 = TimeInt::now().milliseconds_from(&start);
    let bts_gz = match encoder.finish() {
        Ok(v) => v,
        Err(e) => return Err(format!("gzip::zip_bytes_to_file {file_gz} encoding error: {:?}", e).as_str())?,
    };
    // let millsec2 = TimeInt::now().milliseconds_from(&start) - millsec1;

    // println!("耗时: {millsec1} | {millsec2}, {} 压缩成 {}", bts_raw.len(), bts_gz.len());

    file_io::write_bytes(&bts_gz, file_gz)
}


pub fn zip_file_to_file(file_raw: &str, file_gz: &str) -> IResult {
    let mut encoder = GzEncoder::new(vec![], Compression::default());
    let bts_raw = file_io::read_bytes(&file_raw)?;
    
    match encoder.write_all(&bts_raw) {
        Ok(_) => (),
        Err(e) => return Err(format!("gzip::zip_file_to_file {file_gz} encoding error: {:?}", e).as_str())?,
    }
    let bts_gz = match encoder.finish() {
        Ok(v) => v,
        Err(e) => return Err(format!("gzip::zip_file_to_file {file_gz} encoding error: {:?}", e).as_str())?,
    };
    file_io::write_bytes(&bts_gz, file_gz)
}





#[test]
fn test_decode_file_20230510() {
    let file_gz = "Y:/20230510/001.log.gz";
    let bts_raw = unzip_file_to_bytes(file_gz).unwrap();
    println!("len = {}", bts_raw.len());
}
#[test]
fn test_zip_file_to_file_20230530() {
    let file_raw = "D:/temp/2000977.bin";
    let file_gz = "D:/temp/2000977.bin.gz";
    zip_file_to_file(file_raw, file_gz).unwrap();
}

#[test]
fn test_zip_bytes_to_file_20230601() {
    let mut bts_raw = vec![];
    for _ in 0..256 {
        for val in 0..256 {
            bts_raw.push(val as u8);
        }
    }
    let file_gz = "D:/temp/test.gz";
    zip_bytes_to_file(bts_raw, file_gz).unwrap();
}


